`include "defines.svh"

module Core (
    input   logic               clock,
    input   logic               reset,

    // Interrupts
    input   logic               clint_msi, // from CLINT
    input   logic               clint_mti, // from CLINT

    output  logic [63:0]        debug_wb_pc,
    output  logic               debug_wb_valid,

    // Commit
    output  logic [63:0]        icache_miss_count,
    output  logic [63:0]        dcache_miss_count,
    output  logic [63:0]        commit_inst_count,
    output  logic [63:0]        mmio_inst_count,
    output  logic [63:0]        mem_inst_count,
    output  logic               commit_valid,
    output  logic [63:0]        commit_pc,
    output  logic [31:0]        commit_inst,
    output  logic               commit_skip_ref,

    // InstBus interface
    output  logic               ibus_req,
    output  logic               ibus_op,
    output  logic [2:0]         ibus_size,
    output  logic [7:0]         ibus_mask,
    output  logic [31:0]        ibus_addr,
    output  logic [63:0]        ibus_wdata,
    input   logic [63:0]        ibus_rdata,
    input   logic               ibus_addr_ok,
    input   logic               ibus_data_ok,
    output  logic               ibus_uncache,
    input   logic               ibus_cache_miss,
    input   logic               ibus_load_fault,
    input   logic               ibus_store_fault,

    // DataBus interface
    output  logic               dbus_req,
    output  logic               dbus_op,
    output  logic [2:0]         dbus_size,
    output  logic [7:0]         dbus_mask,
    output  logic [31:0]        dbus_addr,
    output  logic [63:0]        dbus_wdata,
    input   logic [63:0]        dbus_rdata,
    input   logic               dbus_addr_ok,
    input   logic               dbus_data_ok,
    output  logic               dbus_uncache,
    input   logic               dbus_cache_miss,
    input   logic               dbus_load_fault,
    input   logic               dbus_store_fault
);

/* ************************ StageIF <=> StageID ************************ */
    // StageID -> StageIF
    logic                       id2if_allow;
    logic [`BJ_BUS_WD-1:0]      bj_bus;
    // StageIF -> StageID
    logic                       if2id_fired;
    logic [`IF2ID_BUS_WD-1:0]   if2id_bus;
/* ************************ StageIF <=> StageID ************************ */


/* ************************ StageID <=> StageEX ************************ */
    // StageID -> StageEX
    logic                       id2ex_valid;
    logic [`ID2EX_BUS_WD-1:0]   id2ex_bus;
    // StageEX -> StageID
    logic                       ex2id_allow;
/* ************************ StageID <=> StageEX ************************ */


/* ************************ StageEX <=> StageMA ************************ */
    // StageEX -> StageMA
    logic                       ex2ma_valid;
    logic [`EX2MA_BUS_WD-1:0]   ex2ma_bus;
    // StageMA -> StageEX
    logic                       ma2ex_allow;
/* ************************ StageEX <=> StageMA ************************ */


/* ************************ StageMA <=> StageWB ************************ */
    // StageWB -> StageMA
    logic                       wb2ma_allow;
    // StageMA -> StageWB
    logic                       ma2wb_valid;
    logic [`MA2WB_BUS_WD-1:0]   ma2wb_bus;
/* ************************ StageMA <=> StageWB ************************ */


/* ************************ StageID <=> Regfile ************************ */
    // StageID -> Regfile
    logic [`ID2RF_BUS_WD-1:0]   id2rf_bus;
    assign  { id_rf_raddr1, id_rf_raddr2 } = id2rf_bus;

    // Regfile -> StageID
    logic [`RF2ID_BUS_WD-1:0]   rf2id_bus;
    assign  rf2id_bus = { id_rf_rdata1, id_rf_rdata2 };
/* ************************ StageID <=> Regfile ************************ */


/* ************************ StageWB <=> Regfile ************************ */
    logic [`WB2RF_BUS_WD-1:0]   wb2rf_bus;
    assign  { wb_rf_we, wb_rf_waddr, wb_rf_wdata } = wb2rf_bus;
/* ************************ StageWB <=> Regfile ************************ */


/* ************************ Forward & Block ************************ */
    // StageEX -> StageID @ Forward & Block
    logic [`EX_RF_HZD_BUS_WD-1:0]   ex_rf_hzd_bus;
    logic [`EX_CSR_BLK_BUS_WD-1:0]  ex_csr_blk_bus;

    // StageMA -> StageID @ Forward & Block
    logic [`MA_RF_HZD_BUS_WD-1:0]   ma_rf_hzd_bus;
    logic [`MA_CSR_BLK_BUS_WD-1:0]  ma_csr_blk_bus;

    // StageWB -> StageID @ Forward & Block
    logic [`WB_RF_HZD_BUS_WD-1:0]   wb_rf_hzd_bus;
    logic [`WB_CSR_BLK_BUS_WD-1:0]  wb_csr_blk_bus;
/* ************************ Forward & Block ************************ */


/* ************************ Cancel Flag ************************ */
    logic   id_cancel;
    logic   ex_cancel;
    logic   ma_cancel;
    logic   wb_cancel;
/* ************************ Cancel Flag ************************ */


/* -------------------------------- Regfile -------------------------------- */
    logic           wb_rf_we;
    logic [4:0]     wb_rf_waddr;
    logic [63:0]    wb_rf_wdata;
    logic [4:0]     id_rf_raddr1;
    logic [63:0]    id_rf_rdata1;
    logic [4:0]     id_rf_raddr2;
    logic [63:0]    id_rf_rdata2;

    Regfile regfile (
        .clock      (clock),
        .reset      (reset),

        .we         (wb_rf_we),
        .waddr      (wb_rf_waddr),
        .wdata      (wb_rf_wdata),

        .raddr1     (id_rf_raddr1),
        .rdata1     (id_rf_rdata1),
        .raddr2     (id_rf_raddr2),
        .rdata2     (id_rf_rdata2)
    );
/* -------------------------------- Regfile -------------------------------- */


/* -------------------------------- CSR -------------------------------- */
    logic [11:0]                csr_raddr;
    logic [63:0]                csr_rdata;
    logic [`WB2CSR_BUS_WD-1:0]  wb2csr_bus;
    logic                       csr_taken;
    logic [63:0]                csr_target;
    logic [1:0]                 csr_intr;

    CSR csr (
        .clock      (clock),
        .reset      (reset),

        .csr_rdata  (csr_rdata),
        .csr_raddr  (csr_raddr),

        .wb2csr_bus (wb2csr_bus),

        .csr_taken  (csr_taken),
        .csr_target (csr_target),

        .clint_msi  (clint_msi),
        .clint_mti  (clint_mti),
        .csr_intr   (csr_intr)
    );
/* -------------------------------- CSR -------------------------------- */


/* -------------------------------- Stage IF -------------------------------- */
    StageIF stage_if (
        .clock              (clock),
        .reset              (reset),

        // StageID -> StageIF
        .id2if_allow        (id2if_allow),
        .bj_bus             (bj_bus),

        // StageIF -> StageID
        .if2id_fired        (if2id_fired),
        .if2id_bus          (if2id_bus),

        // StageID -> StageIF @ Cancel Flag
        .id_cancel          (id_cancel),
        // StageEX -> StageIF @ Cancel Flag
        .ex_cancel          (ex_cancel),
        // StageMA -> StageIF @ Cancel Flag
        .ma_cancel          (ma_cancel),
        // StageWB -> StageIF @ Cancel Flag
        .wb_cancel          (wb_cancel),

        // CSR -> StageIF
        .csr_taken          (csr_taken),
        .csr_target         (csr_target),

        // to InstBus
        .ibus_req           (ibus_req),
        .ibus_op            (ibus_op),
        .ibus_size          (ibus_size),
        .ibus_mask          (ibus_mask),
        .ibus_addr          (ibus_addr),
        .ibus_wdata         (ibus_wdata),
        .ibus_rdata         (ibus_rdata),
        .ibus_addr_ok       (ibus_addr_ok),
        .ibus_data_ok       (ibus_data_ok),
        .ibus_uncache       (ibus_uncache),
        .ibus_cache_miss    (ibus_cache_miss),
        .ibus_load_fault    (ibus_load_fault),
        .ibus_store_fault   (ibus_store_fault)
    );
/* -------------------------------- Stage IF -------------------------------- */


/* -------------------------------- Stage ID -------------------------------- */
    StageID stage_id (
        .clock              (clock),
        .reset              (reset),

        // StageID -> StageIF
        .id2if_allow        (id2if_allow),
        .bj_bus             (bj_bus),

        // StageIF -> StageID
        .if2id_fired        (if2id_fired),
        .if2id_bus          (if2id_bus),

        // StageID -> StageEX
        .id2ex_valid        (id2ex_valid),
        .id2ex_bus          (id2ex_bus),

        // StageEX -> StageID
        .ex2id_allow        (ex2id_allow),

        // StageID -> Regfile
        .id2rf_bus          (id2rf_bus),

        // Regfile -> StageID
        .rf2id_bus          (rf2id_bus),

        // StageID -> StageIF @ Cancel Flag
        .id_cancel          (id_cancel),

        // CSR -> StageID
        .csr_raddr          (csr_raddr),
        .csr_rdata          (csr_rdata),

        // StageEX -> StageID @ Forward & Block
        .ex_rf_hzd_bus      (ex_rf_hzd_bus),
        .ex_csr_blk_bus     (ex_csr_blk_bus),

        // StageMA -> StageID @ Forward & Block
        .ma_rf_hzd_bus      (ma_rf_hzd_bus),
        .ma_csr_blk_bus     (ma_csr_blk_bus),

        // StageWB -> StageID @ Forward & Block
        .wb_rf_hzd_bus      (wb_rf_hzd_bus),
        .wb_csr_blk_bus     (wb_csr_blk_bus),

        // CSR -> StageID
        .csr_taken          (csr_taken),
        .csr_intr           (csr_intr)
    );
/* -------------------------------- Stage ID -------------------------------- */


/* -------------------------------- Stage EX -------------------------------- */
    StageEX stage_ex (
        .clock          (clock),
        .reset          (reset),

        // StageEX -> StageMA
        .ex2ma_valid    (ex2ma_valid),
        .ex2ma_bus      (ex2ma_bus),

        // StageMA -> StageEX
        .ma2ex_allow    (ma2ex_allow),

        // StageEX -> StageID
        .ex2id_allow    (ex2id_allow),

        // StageID -> StageEX
        .id2ex_valid    (id2ex_valid),
        .id2ex_bus      (id2ex_bus),

        // StageEX -> StageIF @ Cancel Flag
        .ex_cancel    (ex_cancel),

        // CSR -> StageEX
        .csr_taken      (csr_taken),

        // StageEX -> StageID @ Forward & Block
        .ex_rf_hzd_bus  (ex_rf_hzd_bus),
        .ex_csr_blk_bus (ex_csr_blk_bus),

        // StageMA -> StageEX @ Cancel Flag
        .ma_cancel      (ma_cancel),

        // StageWB -> StageEX @ Cancel Flag
        .wb_cancel      (wb_cancel),

        // to DataBus
        .dbus_req       (dbus_req),
        .dbus_op        (dbus_op),
        .dbus_size      (dbus_size),
        .dbus_mask      (dbus_mask),
        .dbus_addr      (dbus_addr),
        .dbus_wdata     (dbus_wdata),
        .dbus_addr_ok   (dbus_addr_ok),
        .dbus_uncache   (dbus_uncache),
        .dbus_cache_miss(dbus_cache_miss)
    );
/* -------------------------------- Stage EX -------------------------------- */


/* -------------------------------- Stage MA -------------------------------- */
    StageMA stage_ma (
        .clock              (clock),
        .reset              (reset),

        // StageMA -> StageEX
        .ma2ex_allow        (ma2ex_allow),

        // StageEX -> StageMA
        .ex2ma_valid        (ex2ma_valid),
        .ex2ma_bus          (ex2ma_bus),

        // StageMA -> StageWB
        .ma2wb_valid        (ma2wb_valid),
        .ma2wb_bus          (ma2wb_bus),

        // StageWB -> StageMA
        .wb2ma_allow        (wb2ma_allow),

        // CSR -> StageMA
        .csr_taken          (csr_taken),

        // StageMA -> StageID @ Forward & Block
        .ma_rf_hzd_bus      (ma_rf_hzd_bus),
        .ma_csr_blk_bus     (ma_csr_blk_bus),

        // StageMA -> StageIF/EX @ Cancel Flag
        .ma_cancel          (ma_cancel),

        // from DataBus
        .dbus_rdata         (dbus_rdata),
        .dbus_data_ok       (dbus_data_ok),
        .dbus_load_fault    (dbus_load_fault),
        .dbus_store_fault   (dbus_store_fault)
    );
/* -------------------------------- Stage MA -------------------------------- */


/* -------------------------------- Stage WB -------------------------------- */
    StageWB stage_wb (
        .clock              (clock),
        .reset              (reset),

        // for debug pipeline
        .debug_wb_pc        (debug_wb_pc),
        .debug_wb_valid     (debug_wb_valid),

        // StageWB -> Regfile
        .wb2rf_bus          (wb2rf_bus),

        // StageMA -> StageWB
        .ma2wb_valid        (ma2wb_valid),
        .ma2wb_bus          (ma2wb_bus),

        // StageWB -> StageMA
        .wb2ma_allow        (wb2ma_allow),

        // CSR -> StageWB
        .csr_taken          (csr_taken),

        // StageWB -> CSR
        .wb2csr_bus         (wb2csr_bus),

        // StageWB -> StageIF/EX @ Cancel Flag
        .wb_cancel          (wb_cancel),

        // StageWB -> StageID @ Forward & Block
        .wb_rf_hzd_bus      (wb_rf_hzd_bus),
        .wb_csr_blk_bus     (wb_csr_blk_bus),

        // Commit
        .icache_miss_count  (icache_miss_count),
        .dcache_miss_count  (dcache_miss_count),
        .commit_inst_count  (commit_inst_count),
        .mmio_inst_count    (mmio_inst_count),
        .mem_inst_count     (mem_inst_count),
        .commit_valid       (commit_valid),
        .commit_pc          (commit_pc),
        .commit_inst        (commit_inst),
        .commit_skip_ref    (commit_skip_ref)
    );
/* -------------------------------- Stage WB -------------------------------- */

endmodule
